/* 测试cobj */
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <metalc/block/cobj.h>
cobj_ord_t *p;
COBJ_EXT(ext, p, 0x1000)

#define TEST_MEMSIZE 0x4000
char test_memspace[TEST_MEMSIZE] PAGE_ALIGNED;

void test_ext(){

	p = malloc(BIT(48-16));
	assert(p);

	const cobj_oufun_t * tmp = OUFUN_OF(ext);

	assert(tmp->mocupysz() == 0);

	/* 初始化和设置 */
	uvoid *uptr = tmp->set_cobj(test_memspace, TEST_MEMSIZE, 0);
	assert(uptr == test_memspace);
	
	/* 设置终止 */
	tmp->set_cobj(test_memspace + TEST_MEMSIZE, 0, 1);

	/* 获得原始指针和大小 */
	size_t size;
	void *ptr = tmp->uptr2ptr(uptr);
	size = tmp->ptr_getsize(ptr);
	assert(size == TEST_MEMSIZE);
	assert(ptr == uptr);

	/* merge错误情况 */
	size_t merge_size = tmp->merge_next(ptr, TEST_MEMSIZE);
	assert(merge_size == TEST_MEMSIZE);

	/* split失败 */
	assert(NULL == tmp->split(ptr, TEST_MEMSIZE, TEST_MEMSIZE*2, 0));
	// assert(NULL == tmp->split(ptr, TEST_MEMSIZE, TEST_MEMSIZE/3));

	/* split成功 */
	void *ptr2 = tmp->split(ptr, TEST_MEMSIZE, TEST_MEMSIZE/2, 0);
	assert(ptr2 == ptr + TEST_MEMSIZE/2);

	uptr = tmp->set_cobj(ptr2, TEST_MEMSIZE/2, 1);
	assert(uptr == ptr2);

	void *tmpptr = tmp->uptr2ptr(uptr);
	size = tmp->ptr_getsize(tmpptr);
	assert(tmpptr == ptr2);
	assert(size == TEST_MEMSIZE/2);

	/* 尝试合并失败 */
	size = tmp->merge_next(ptr, TEST_MEMSIZE/2);
	assert(size == TEST_MEMSIZE/2);

	/* 设置free */
	uptr = tmp->set_cobj(ptr2, size, 0);
	assert(uptr == ptr2);
	
	/* 尝试合并成功 */
	size = tmp->merge_next(ptr, TEST_MEMSIZE/2);
	assert(size == TEST_MEMSIZE);

	uptr = ptr;
	tmpptr = tmp->uptr2ptr(uptr);
	size = tmp->ptr_getsize(tmpptr);
	assert(tmpptr == ptr);
	assert(size == TEST_MEMSIZE);
}


void test_in(){

	const cobj_oufun_t * tmp = OUFUN_OF(cobjin);

	__memset(test_memspace, 0, sizeof(cobj_t));
	assert(tmp->mocupysz() == sizeof(cobj_t));

	/* 初始化和设置 */
	uvoid *uptr = tmp->set_cobj(test_memspace, TEST_MEMSIZE - 2 * sizeof(cobj_t), 0);
	// printf("%lx, %lx, %lx, %lx\n", test_memspace, uptr, sizeof(cobj_t), &test_memspace[sizeof(cobj_t)]);
	assert(uptr == &test_memspace[sizeof(cobj_t)]);
	
	/* 设置终止 */
	tmp->set_cobj(test_memspace + TEST_MEMSIZE - 2 * sizeof(cobj_t), sizeof(cobj_t), 1);

	/* 获得原始指针和大小 */
	size_t size;
	void *ptr = tmp->uptr2ptr(uptr);
	size = tmp->ptr_getsize(ptr);
	assert(size == TEST_MEMSIZE - 2 * sizeof(cobj_t));
	assert(ptr == uptr - sizeof(cobj_t));

	/* merge错误情况 */
	size_t merge_size = tmp->merge_next(ptr, TEST_MEMSIZE - sizeof(cobj_t));
	assert(merge_size == TEST_MEMSIZE - sizeof(cobj_t));

	/* split失败 */
	assert(NULL == tmp->split(ptr, TEST_MEMSIZE, TEST_MEMSIZE*2, 0));

	/* split成功 */
	void *ptr2 = tmp->split(ptr, TEST_MEMSIZE - sizeof(cobj_t), TEST_MEMSIZE/2, 0);
	assert(ptr2 == ptr + TEST_MEMSIZE/2);


	uptr = tmp->set_cobj(ptr2, TEST_MEMSIZE/2 - sizeof(cobj_t), 1);
	assert(uptr == ptr2 + sizeof(cobj_t));


	void *tmpptr = tmp->uptr2ptr(uptr);
	size = tmp->ptr_getsize(tmpptr);
	assert(tmpptr == ptr2);
	assert(size == TEST_MEMSIZE/2 - sizeof(cobj_t));

	/* 尝试合并失败 */
	size = tmp->merge_next(ptr, TEST_MEMSIZE/2);
	assert(size == TEST_MEMSIZE/2);

	/* 设置free */
	uptr = tmp->set_cobj(ptr2, TEST_MEMSIZE/2 - sizeof(cobj_t), 0);
	assert(uptr == ptr2 + sizeof(cobj_t));
	
	assert(tmp->get_prev(ptr2, TEST_MEMSIZE/2 - sizeof(cobj_t)) == ptr);

	/* 尝试合并成功 */
	size = tmp->merge_next(ptr, TEST_MEMSIZE/2);
	assert(size == TEST_MEMSIZE - sizeof(cobj_t));

	uptr = ptr + sizeof(cobj_t);

	tmpptr = tmp->uptr2ptr(uptr);
	size = tmp->ptr_getsize(tmpptr);
	assert(tmpptr == ptr);
	assert(size == TEST_MEMSIZE - sizeof(cobj_t));


	/* 只合并next不合并prev? */

}

int main(){
	// test_ext(); /* 申请内存过大可能会崩 */
	test_in();
	printf("all test ok\n");
	return 0;
}